#include "processor.h"


void processor::writeback(unsigned int lane_number) {
   unsigned int index;

   // Check if there is an instruction in the Writeback Stage of the specified Execution Lane.
   if (Execution_Lanes[lane_number].wb.valid) {

      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      // Get the instruction's index into PAY.
      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      index = Execution_Lanes[lane_number].wb.index;

      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      // FIX_ME #15
      // Resolve branches.
      //
      // Background: Here we are resolving a branch that previously made a checkpoint.
      //
      // If the branch was correctly predicted, then resolution consists of two steps:
      // * Tell each renamer module that the branch resolved correctly, so that it frees its corresponding checkpoint.
      // * Clear the branch's bit in the branch masks of instructions in the pipeline. Specifically, this
      //   involves instructions from the Rename Stage (where branch masks are first assigned) to the
      //   Writeback Stage (instructions leave the pipeline after Writeback, although they still hold
      //   entries in the Active List and Load/Store Queues).
      //
      // If the branch was mispredicted, then resolution consists of two high-level steps:
      // * Recover key units: the Fetch Unit, the renamer modules (RMTs, FLs, ALs), and the LSU.
      // * Squash instructions in the pipline that are logically after the branch -- those instructions
      //   that have the branch's bit in their branch masks -- meanwhile clearing that bit. Also, all
      //   instructions in the frontend stages are automatically squashed since they are by definition
      //   logically after the branch.
      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      if (PAY.buf[index].checkpoint) {
         if (PERFECT_BRANCH_PRED) {
	    if (!wait_for_trap)
	       assert(PAY.buf[index].next_pc == PAY.buf[index].c_next_pc);

	    // FIX_ME #15a
	    // The simulator is running in perfect branch prediction mode, therefore, all branches are correctly predicted.
	    // The assertion immediately above confirms that the prediction (next_pc is the predicted target)
	    // matches the outcome (c_next_pc is the calculated target).
	    //
	    // Tips:
	    // 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
	    // 2. Call the resolve() function of both the integer and floating-point renamer modules so that they free
	    //    the branch's checkpoint. Recall that the arguments to resolve() are:
	    //    * Active List index
	    //    * The branch's ID
	    //    * Whether or not the branch was predicted correctly: in this case it is correct
	    // 3. Do NOT worry about clearing the branch's bit in the branch masks of instructions in the pipeline.
	    //    This is unnecessary since instructions don't need accurate branch masks in perfect branch prediction
	    //    mode... since they are never squashed anyway.
 
	    REN_INT->resolve(PAY.buf[index].AL_index_int, PAY.buf[index].branch_ID, true);
	    REN_FP->resolve(PAY.buf[index].AL_index_fp, PAY.buf[index].branch_ID, true);

         }
	 else if (PAY.buf[index].next_pc == PAY.buf[index].c_next_pc) {
	    // FIX_ME #15b
	    // The simulator is running in real branch prediction mode, and the branch was correctly predicted.
	    // You can see this in the comparison above: the prediction (next_pc is the predicted target)
	    // matches the outcome (c_next_pc is the calculated target).
	    //
	    // Branch was predicted correctly.
	    //
	    // Tips:
	    // 1. See #15a, item 1.
	    // 2. See #15a, item 2.
	    // 3. Clear the branch's bit in the branch masks of instructions in the pipeline.
	    //    To do this, call the resolve() function with the appropriate arguments. This function does the work for you.
	    //    * resolve() is a private function of the processor class, therefore, just call it literally as 'resolve'.
	    //    * resolve() takes two arguments. The first argument is the branch's ID. The second argument is a flag that
	    //      indicates whether or not the branch was predicted correctly: in this case it is correct.
	    //    * See processor.h for details about the two arguments of resolve().

		 REN_INT->resolve(PAY.buf[index].AL_index_int, PAY.buf[index].branch_ID, true);
		 REN_FP->resolve(PAY.buf[index].AL_index_fp, PAY.buf[index].branch_ID, true);


		resolve(PAY.buf[index].branch_ID, true);
	 }
	 else {
	    // Branch was mispredicted.

	    // Roll-back the fetch unit: PC and branch predictor.
	    pc = PAY.buf[index].c_next_pc;					// PC gets the correct target of the resolved branch.
	    BP.fix_pred(PAY.buf[index].pred_tag, PAY.buf[index].c_next_pc);	// Roll-back the branch predictor to the point of the resolved branch.

	    // FIX_ME #15c
	    // The simulator is running in real branch prediction mode, and the branch was mispredicted.
	    // Recall the two high-level steps that are necessary in this case:
	    // * Recover key units: the Fetch Unit, the renamer modules (RMTs, FLs, ALs), and the LSU.
	    //   The Fetch Unit is recovered in the statements immediately preceding this comment (please study them for knowledge).
	    //   The LSU is recovered in the statements immediately following this comment (please study them for knowledge).
	    //   Your job for #15c will be to recover the renamer modules, in between.
            // * Squash instructions in the pipeline that are logically after the branch. You will do this too, in #15d below.
	    //
	    // Restore the RMT, FL, and AL.
	    //
	    // Tips:
	    // 1. See #15a, item 1.
	    // 2. See #15a, item 2 -- EXCEPT in this case the branch was mispredicted, so specify not-correct instead of correct.
	    //    This will restore the RMT, FL, and AL, and also free this and future checkpoints... etc.

	    REN_INT->resolve(PAY.buf[index].AL_index_int, PAY.buf[index].branch_ID, false);
	    REN_FP->resolve(PAY.buf[index].AL_index_fp, PAY.buf[index].branch_ID, false);

	    // Restore the LQ/SQ.
	    LSU.restore(PAY.buf[index].LQ_index, PAY.buf[index].LQ_phase, PAY.buf[index].SQ_index, PAY.buf[index].SQ_phase);

	    // FIX_ME #15d
	    // Squash instructions after the branch in program order, in all pipeline registers and the IQs.
	    //
	    // Tips:
	    // 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
	    // 2. Squash instructions after the branch in program order.
	    //    To do this, call the resolve() function with the appropriate arguments. This function does the work for you.
	    //    * resolve() is a private function of the processor class, therefore, just call it literally as 'resolve'.
	    //    * resolve() takes two arguments. The first argument is the branch's ID. The second argument is a flag that
	    //      indicates whether or not the branch was predicted correctly: in this case it is not-correct.
	    //    * See processor.h for details about the two arguments of resolve().

	    resolve(PAY.buf[index].branch_ID, false);

	    // Rollback PAY to the point of the branch.
	    PAY.rollback(index);
	 }
      }

      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      // FIX_ME #16
      // Set completed bits in Active Lists.
      //
      // Tips:
      // 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
      // 2. Set the completed bit for this instruction in both the integer Active List and floating-point Active List.
      //////////////////////////////////////////////////////////////////////////////////////////////////////////

      REN_INT->set_complete(PAY.buf[index].AL_index_int);
      REN_FP->set_complete(PAY.buf[index].AL_index_fp);


      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      // Remove the instruction from the Execution Lane.
      //////////////////////////////////////////////////////////////////////////////////////////////////////////
      Execution_Lanes[lane_number].wb.valid = false;
   }
}
